#include <linux/module.h>
#include <linux/pci.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/msi.h>
#include <linux/mutex.h>
#define EN_CDEV     // 使能 字符设备
#ifdef EN_CDEV
#include <linux/cdev.h>
#endif // EN_CDEV
#define EN_IRQ      // 使能 IRQ
#ifdef EN_IRQ
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#endif  // EN_IRQ
#define EN_DMA      // 使能 DMA
#define EN_AD       // 使能 AD

#define DRIVER_NAME         "pcie_cdev_ad"
#define PCI_MAX_BARS        6           // PCI标准定义最多6个BAR
#define PCI_BAR0            0
#define PCI_BAR1            1
#define MAX_DEVICES         1           // 支持的最大设备数


#ifdef EN_IRQ
/*
 * 系统支持的最大中断资源数量：
 *  1. MSI-X: PCI 3.0+ 规范支持的最大向量数 (2048)
 *  2. MSI:   PCI 规范支持的最大向量数 (32)
 *  3. Legacy: 传统PCI设备支持的最大中断数 (1)
 * 注意：实际可用数量受设备能力和系统资源限制
 */
#define IRQ_MAX_VEC_MSIX    2048
#define IRQ_MAX_VEC_MSI     32
#define IRQ_MAX_VEC_LGCY    1
#define IRQ_NAME            "irq_ad"

// 中断寄存器定义
#define IRQ_MSI_MASK_REG    0x5C
// 中断向量定义
#define IRQ_VEC_MSI_AD      0           // AD 中断向量
#endif // EN_IRQ


#ifdef EN_DMA
#define DMA_DEFAULT_SIZE                (256 * 1024)    // 256KB
#define DMA_PACKET_LEN_MAX              (1024 * 4)      // 数据包长度最大值，位宽 10bit，单位 DW，共 2^10 * 4 = 4096byte
#define DMA_FRAME_SIZE                  (64*1024)       // 64KB

#define DMA_CPU_PHYS_ADDR_LOW_REG       0x200           // 存储 CPU 内存低 32 位地址寄存器
#define DMA_CPU_PHYS_ADDR_HIGH_REG      0x204           // 存储 CPU 内存高 32 位地址寄存器
#define DMA_FPGA_RAM_ADDR_REG           0x210           // CplD 数据在 RAM 的初始地址寄存器
#define DMA_FPGA_RAM_LEN_REG            0x220           // CplD 数据在 RAM 的数据包长度寄存器(单位DW)
#define DMA_FPGA_STATUS_REG             0x230           // 状态寄存器
#define DMA_FPGA_DATA_TYPE_REG          0x240           // 数据类型寄存器

#define DMA_WAIT_DATA_CPL_CNT           100             // 等待数据操作完成，读取状态寄存器次数
#endif // EN_DMA


#ifdef EN_AD
// AD DMA 定义
#define DMA_SIZE_AD         (64 * 1024)    // 128KByte
#define AD_CHANNEL          16
// AD 指令定义
#define AD_COMM_START_AD    0x1111          // 开始 AD 采集
#define AD_COMM_STOP_AD     0x2222          // 停止 AD 采集
/* AD 寄存器*/
enum ad_reg_t {
    AD_COMM_OFFSET = 0x08,                          /* AD 指令寄存器偏移 */
    AD_CH_VAL_OFFSET = 0x38,                        /* AD 通道数据寄存器偏移*/
    AD_RANGE_OFFSET = 0x44,                         /* AD 范围寄存器偏移 */
    AD_SAMPLE_OSR_OFFSET = 0x48,                    /* AD 采样间隔和过采样寄存器偏移 */
    AD_MSI_IRQ_MSK = 0x60,                          /* AD MSI 中断屏蔽寄存器偏移 */
};
#define AD_SAMPLE_OSR_MASK          0x00000700      /* AD 过采样 */
#define AD_SAMPLE_INTERVAL_MASK     0x0000FFFF      /* AD 采样间隔 */
#define AD_SAMPLE_OSR_SHIFT         16

#define AD_DEF_SAMPLE_INTERVAL      1000            /* AD 默认采样间隔，0~65535us */
#define AD_DEF_OSR                  0               /* AD 默认过采样，0, 2, 4, 8, 16, 32, 64, 128 */
#define AD_DEF_RANGE                "10"            /* AD 默认量程，"10": ±10V, "2.5": ±2.5V, "5": ±5V */

#define AD_RANGE_10V                0x00
#define AD_RANGE_2V5                0x01
#define AD_RANGE_5V                 0X02

#define AD_RANGE_10V_LSB            305             /* 305uV */
#define AD_RANGE_2V5_LSB            76              /* 76uV */
#define AD_RANGE_5V_LSB             152             /* 152uV */
#endif // EN_AD


#ifdef EN_CDEV
struct char_dev_t {
    struct device *dev;     // 设备描述符
    char *name;             // 设备名
    struct cdev cdev;       // 字符设备
    dev_t devno;            // 设备号
    struct class *cls;      // 设备类
};
#endif // EN_CDEV

#ifdef EN_IRQ
// 中断数据结构
struct irq_t {
    struct device *dev;                                     // 设备描述符
    void __iomem *reg_base;                                 // 寄存器空间映射（内核虚拟地址）
    int mode;                                               // 中断模式
    int num;                                                // 中断数量
    int vector[IRQ_MAX_VEC_MSIX];                           // 中断向量
    atomic_t count;                                         // 中断计数
    wait_queue_head_t wait_queue;                           // 中断等待队列
    struct msix_entry msix_entries[IRQ_MAX_VEC_MSIX];       // MSI-X 表项
    struct work_struct work_queue;                          // 工作队列(中断下半部)
};
#endif  // EN_IRQ

#ifdef EN_DMA
// 中断数据结构
struct  dma_t {
    void __iomem *reg_base;             // 寄存器空间映射（内核虚拟地址）
    dma_addr_t alloc_phys;              // DMA 申请的内存物理地址（给FPGA用）
    void *alloc_virt;                   // DMA 申请的内存虚拟地址（内核用）
    size_t pl_size;                     // DMA 内存大小（默认256KB）
    dma_addr_t ps_addr;                 // DMA 设置的内存物理地址（给FPGA用）
    /* DMA数据包最大4KB */
    u32 pkt_addr;                       // DMA 设置的 FPGA 数据包源地址
    u32 pkt_len;                        // DMA 设置的 FPGA 数据包长度（默认4KB>>2-1）
    u32 pkt_size;                       // DMA 设置的 FPGA 数据包大小（默认4KB）
    u8 addr_type;                       // CPU 设置的 地址长度，0 - 32位地址，1 - 64位地址
    u32 pkt_cnt;                        // DMA 数据包计数
    /* DMA多包数据组成一帧数据 */
    u32 frame_size;                     // DMA 帧大小
    u32 frame_cnt;                      // DMA 帧计数
    bool frame_done;                    // DMA 帧完成标志（1:完成，0:未完成）
    wait_queue_head_t wq_frame;         // 等待队列（等待帧完成）
    /* DMA内存组成环形缓冲区 */
    spinlock_t frame_lock;              // 缓冲区自旋锁
    u32 frame_head;                     // DMA 帧头，记录写入位置
    u32 frame_tail;                     // DMA 帧尾，记录读取位置
};
#endif // EN_DMA

#ifdef EN_AD
// AD 数据结构
struct ad_t {
    u8 no;                              // 设备编号
    void __iomem *reg_base;             // 寄存器基地址
    u32 pkt_size;                       // 数据包大小
    u32 cpl_cnt;                        // 完成计数
    u32 cpl_all;                        // 全部完成计数
    u32 addr;                           // 数据地址
    u32 (*read_reg)(const struct ad_t *priv, enum ad_reg_t reg);
    void (*write_reg)(const struct ad_t *priv, enum ad_reg_t reg, u32 val);
    u8 range[AD_CHANNEL];
};
#endif // EN_AD

// 设备特定数据结构
struct pcie_t {
    struct device *dev;                         // 设备描述符
    char name[64];                              // 唯一设备名称
    void __iomem *bar[PCI_MAX_BARS];            // 映射的寄存器基地址
    resource_size_t bar_len[PCI_MAX_BARS];      // 寄存器区域长度
    struct mutex lock;                          // 同步机制(互斥锁)
#ifdef EN_CDEV
    struct char_dev_t char_dev;     // 字符设备
#endif // EN_CDEV
#ifdef EN_IRQ
    struct irq_t irq;               // 中断
#endif // EN_IRQ
#ifdef EN_DMA
    struct dma_t dma;               // DMA
#endif // EN_DMA
#ifdef EN_AD
    struct ad_t ad;                 // AD
#endif // EN_AD
};

// 文件操作函数声明
static int pcie_cdev_open(struct inode *inode, struct file *filp);
static int pcie_cdev_release(struct inode *inode, struct file *filp);
static ssize_t pcie_cdev_read(struct file *filp, char __user *buf, 
                              size_t count, loff_t *ppos);
static ssize_t pcie_cdev_write(struct file *filp, const char __user *buf, 
                               size_t count, loff_t *ppos);
static long pcie_cdev_ioctl(struct file *filp, unsigned int cmd, 
                            unsigned long arg);
#ifdef EN_IRQ
static unsigned int pcie_cdev_poll(struct file *filp, poll_table *wait);
static irqreturn_t drv_irq_isr(int irq, void *dev_id);
#endif // EN_IRQ

// 文件操作结构体
static const struct file_operations pcie_cdev_fops = {
    .owner = THIS_MODULE,
    .open = pcie_cdev_open,
    .release = pcie_cdev_release,
    .read = pcie_cdev_read,
    .write = pcie_cdev_write,
    .unlocked_ioctl = pcie_cdev_ioctl,
#ifdef EN_IRQ
    .poll = pcie_cdev_poll,
#endif // EN_IRQ
    .llseek = no_llseek, // 不支持 seek
};

#ifdef EN_DMA
// DMA开始传输
static int dma_start(struct dma_t *dma) {
    struct pcie_t *priv = container_of(dma, struct pcie_t, dma);
    int ret = 0;
    u32 val = 0;
    u32 i = 0;

    // 设置内存低32位地址（BAR1+0x200）
    val = (u32)(priv->dma.ps_addr & 0xFFFFFFFF);
    iowrite32(val, priv->dma.reg_base + DMA_CPU_PHYS_ADDR_LOW_REG);
    dev_dbg(priv->dev, "Set addr low: 0x%x\n", val);
    // 设置内存高32位地址（BAR1+0x204）
    val = (u32)((priv->dma.ps_addr >> 32) & 0xFFFFFFFF);
    iowrite32(val, priv->dma.reg_base + DMA_CPU_PHYS_ADDR_HIGH_REG);
    dev_dbg(priv->dev, "Set addr high: 0x%x\n", val);
    // 设置CplD初始地址（BAR1+0x210）
    val = (u32)(priv->dma.pkt_addr);
    iowrite32(val, priv->dma.reg_base + DMA_FPGA_RAM_ADDR_REG);
    dev_dbg(priv->dev, "Set CplD addr: 0x%x\n", val);
    // 设置数据包长度（BAR1+0x220）
    val = (u32)(((priv->dma.pkt_len) >> 2) - 1);    // 单位 DW
    iowrite32(val, priv->dma.reg_base + DMA_FPGA_RAM_LEN_REG);
    dev_dbg(priv->dev, "Set packet len: %u bytes\n", val);
    // 设置数据包类型（BAR1+0x240）
    priv->dma.addr_type = ((priv->dma.alloc_phys >> 32) > 0) ? 1 : 0;
    iowrite32(priv->dma.addr_type, priv->dma.reg_base + DMA_FPGA_DATA_TYPE_REG);
    dev_dbg(priv->dev, "Set address type: %d\n", priv->dma.addr_type);
    // 检查DMA状态（BAR1+0x230，1:完成，0:未完成）
    for (i = 0; i < DMA_WAIT_DATA_CPL_CNT; i++) {
        val = ioread32(priv->dma.reg_base + DMA_FPGA_STATUS_REG);
        if (1 == val) {
            dev_dbg(priv->dev, "DMA completed successfully (status=%d cnt=%d).\n", val, i);
            break;
        }
    }
    if (DMA_WAIT_DATA_CPL_CNT == i) {
        dev_info(priv->dev, "DMA failed (status: %u)\n", val);
        ret--;
    }

    return ret;
}
// DMA地址更新，返回值 1：继续DMA开始传输；0：无须继续DMA传输
static int dma_addr_update(struct dma_t *dma)
{
    int ret = 0;

    /* 当前版本要求pkt_len、pkt_size、frame_size固定不变，且可以被pl_size整除！*/
    dma->pkt_cnt = ((dma->pkt_cnt + 1) % (dma->pl_size / dma->pkt_len));
    /* 0~256KB每4KB间隔递增 */
    dma->pkt_addr = (u32)((dma->pkt_cnt % (dma->pl_size / dma->pkt_len)) * dma->pkt_len);
    /* ps_addr初始值为alloc_phys，逐包偏移地址，当大于等于pl_size(256KB)时，恢复初始位置 */
    dma->ps_addr += dma->pkt_len;
    if ((dma->ps_addr + dma->pkt_len) > (dma->alloc_phys + dma->pl_size)) {
        dma->ps_addr = dma->alloc_phys;
    }

    return ret;
}
#endif // EN_DMA

#ifdef EN_AD
const char *ad_range_t[] = {
    "10", "2.5", "5",
};
static int ad_set_range(struct ad_t *ad, u8 channel, const char *range)
{
    struct pcie_t *priv = container_of(ad, struct pcie_t, ad);
    int ret = 0;
    u8 i = 0;
    u32 val = 0;

    if (channel >= AD_CHANNEL) {
        ret = -1;
        goto err_return;
    }
    for (i = 0; i < 3; i++) {
        if (strcmp(range, ad_range_t[i]) == 0) {
            break;
        }
    }
    if (i < 3) {
        ad->range[channel] = i;
        val = ioread32(ad->reg_base + AD_RANGE_OFFSET);
        val &= (~(0x03 << channel));
        val |= (ad->range[channel] << channel);
        iowrite32(val, ad->reg_base + AD_RANGE_OFFSET);
        dev_info(priv->dev, "AD set range %s success.\n", range);
    } else {
        dev_info(priv->dev, "AD set range %s failed!\n", range);
        ret = -2;
        goto err_return;
    }

err_return:
    return ret;
}
const u8 ad_osr[] = {
    0, 2, 4, 8, 16, 32, 64, 128,
};
static int ad_set_osr(struct ad_t *ad, u8 osr)
{
    struct pcie_t *priv = container_of(ad, struct pcie_t, ad);
    int ret = 0;
    u8 i = 0;
    u32 val = 0;

    for (i = 0; i < sizeof(ad_osr); i++) {
        if (osr == ad_osr[i]) {
            break;
        }
    }
    if (i < sizeof(ad_osr)) {
        val = ioread32(ad->reg_base + AD_SAMPLE_OSR_OFFSET);
        val &= AD_SAMPLE_INTERVAL_MASK;
        val |= ((i << AD_SAMPLE_OSR_SHIFT) & AD_SAMPLE_OSR_MASK);
        iowrite32(val, ad->reg_base + AD_SAMPLE_OSR_OFFSET);
        dev_info(priv->dev, "AD set OSR %d success.\n", osr);
    } else {
        dev_info(priv->dev, "AD set OSR %d failed!\n", osr);
        ret = -1;
        goto err_return;
    }

err_return:

    return ret;
}
// 配置采样周期
static int ad_set_samp(struct ad_t *ad, u16 interval)
{
    struct pcie_t *priv = container_of(ad, struct pcie_t, ad);
    int ret = 0;
    u32 val = 0;

    val = ioread32(ad->reg_base + AD_SAMPLE_OSR_OFFSET);
    val &= AD_SAMPLE_OSR_MASK;
    val |= (interval & AD_SAMPLE_INTERVAL_MASK);
    iowrite32(val, ad->reg_base + AD_SAMPLE_OSR_OFFSET);
    dev_info(priv->dev, "AD set sample interval %dus success.\n", interval);

    return ret;
}

// AD初始化
static int ad_init(struct ad_t *ad)
{
    struct pcie_t *priv = container_of(ad, struct pcie_t, ad);
    int ret = 0;
    u8 i = 0;

    ad->reg_base = priv->bar[PCI_BAR0];
    ad_set_samp(ad, AD_DEF_SAMPLE_INTERVAL);
    ad_set_osr(ad, AD_DEF_OSR);
    for (i = 0; i < AD_CHANNEL; i++) {
        ad_set_range(ad, i, AD_DEF_RANGE);
    }

    return ret;
}
#endif // EN_AD


// 打开设备
static int pcie_cdev_open(struct inode *inode, struct file *filp)
{
    struct pcie_t *priv;
    struct char_dev_t *char_dev;

    // 获取与 inode 关联的字符设备
    char_dev = container_of(inode->i_cdev, struct char_dev_t, cdev);
    priv = container_of(char_dev, struct pcie_t, char_dev);
    // 检查设备是否有效
    if (!priv || !priv->dev) {
        return -ENODEV;
    }
    // 记录设备指针
    filp->private_data = priv;
    // 尝试锁定设备
    if (mutex_lock_interruptible(&priv->lock)) {
        return -ERESTARTSYS;
    }
    // 简单的打开计数（实际应用中可能需要更复杂的资源管理）
    dev_info(priv->dev, "Device opened\n");

#ifdef EN_DMA
    // 分配DMA内存（ coherent 内存：物理连续，且内核/设备可访问）
    priv->dma.alloc_virt = dma_alloc_coherent(priv->dev, DMA_DEFAULT_SIZE, &priv->dma.alloc_phys, GFP_KERNEL);
    if (!priv->dma.alloc_virt) {
        dev_err(priv->dev, "Allocate DMA memory failed!\n");
        return -ENOMEM;
    }
    priv->dma.pl_size = DMA_DEFAULT_SIZE;
    priv->dma.ps_addr = priv->dma.alloc_phys;
    priv->dma.pkt_addr = 0;
    priv->dma.pkt_len = DMA_PACKET_LEN_MAX;
    priv->dma.pkt_size = DMA_PACKET_LEN_MAX;
    priv->dma.pkt_cnt = 0;
    priv->dma.frame_size = DMA_FRAME_SIZE;
    priv->dma.frame_cnt = 0;
    priv->dma.frame_head = 0;
    priv->dma.frame_tail = 0;
    priv->dma.frame_done = false;
    init_waitqueue_head(&priv->dma.wq_frame);   // 初始化等待队列（数据帧完成）
    dev_info(priv->dev, "DMA memory allocated: alloc_virt=%p, alloc_phys=0x%0llx, size=%zu\n",
             priv->dma.alloc_virt, (unsigned long long)priv->dma.alloc_phys, priv->dma.pl_size);
#endif // ENABLE_DMA
#ifdef EN_AD
    priv->ad.pkt_size = DMA_SIZE_AD;
    priv->ad.cpl_cnt = 0;
    priv->ad.cpl_all = 0;
#endif // EN_AD

    mutex_unlock(&priv->lock);
    return 0;
}

// 关闭设备
static int pcie_cdev_release(struct inode *inode, struct file *filp)
{
    struct pcie_t *priv = filp->private_data;

    dev_info(priv->dev, "cpl_cnt=%d/%d.\n", priv->ad.cpl_cnt, priv->ad.cpl_all);
    if (priv) {
        mutex_lock(&priv->lock);
        dev_info(priv->dev, "Device closed\n");
        mutex_unlock(&priv->lock);
    }

    return 0;
}

// 读取设备
static ssize_t pcie_cdev_read(struct file *filp, char __user *buf, 
                             size_t count, loff_t *ppos)
{
    struct pcie_t *priv = filp->private_data;
    size_t read_len = 0;
    ssize_t ret = 0;
    unsigned long flags;    // 用于保存中断状态

    if (!priv || !buf) {
        return -EINVAL;
    }
    // 锁保护
    if (mutex_lock_interruptible(&priv->lock)) {
        return -ERESTARTSYS;
    }
    // 检查偏移量是否有效
    if (*ppos > priv->dma.pl_size) {
        ret = 0; // EOF
        goto unlock;
    } else if (*ppos == priv->dma.pl_size) {
        *ppos = 0;
    }
    // 计算实际可读取字节数
    read_len = min(count, (size_t)(priv->dma.pl_size - *ppos));

    // 等待DMA帧完成（中断唤醒）
    if (wait_event_interruptible(priv->dma.wq_frame, priv->dma.frame_done)) {
        dev_err(priv->dev, "DMA frame wait interrupted\n");
        ret = -ERESTARTSYS;
        goto unlock;
    }
    priv->dma.frame_done = false;

    /* 环形缓冲区指针操作，自旋锁保护*/
    spin_lock_irqsave(&priv->dma.frame_lock, flags);    // 获取自旋锁（保存中断状态）
    // 从DMA内存复制数据到用户空间
    if (copy_to_user(buf, priv->dma.alloc_virt + *ppos, read_len)) {
        spin_unlock_irqrestore(&priv->dma.frame_lock, flags);    // 释放自旋锁（恢复中断状态）
        dev_err(priv->dev, "Failed to copy data to user space\n");
        goto unlock;
    }
    priv->ad.cpl_cnt--;
    priv->dma.frame_tail = (priv->dma.frame_tail + priv->dma.frame_size) % priv->dma.pl_size;
    spin_unlock_irqrestore(&priv->dma.frame_lock, flags);       // 释放自旋锁（恢复中断状态）
    // 更新文件位置
    *ppos += read_len;
    ret = read_len;
    dev_dbg(priv->dev, "Read %zu bytes from offset %lld\n", 
           read_len, *ppos - read_len);

unlock:
    mutex_unlock(&priv->lock);

    return ret;
}

// 写入设备
static ssize_t pcie_cdev_write(struct file *filp, const char __user *buf, 
                              size_t count, loff_t *ppos)
{
    struct pcie_t *priv = filp->private_data;
    size_t bytes_written = 0;
    ssize_t ret = 0;
    
    if (!priv || !priv->bar[PCI_BAR0] || !buf) {
        return -EINVAL;
    }
    // 锁保护
    if (mutex_lock_interruptible(&priv->lock)) {
        return -ERESTARTSYS;
    }
    // 检查偏移量是否有效
    if (*ppos >= priv->bar_len[PCI_BAR0]) {
        ret = -EFBIG; // 超出范围
        goto unlock;
    }
    // 计算实际可写入字节数
    bytes_written = min(count, (size_t)(priv->bar_len[PCI_BAR0] - *ppos));
    // 从用户空间复制到寄存器
    if (copy_from_user(priv->bar[PCI_BAR0] + *ppos, buf, bytes_written)) {
        ret = -EFAULT;
        goto unlock;
    }
    // 更新文件位置
    *ppos += bytes_written;
    ret = bytes_written;
    
    dev_dbg(priv->dev, "Wrote %zu bytes to offset %lld\n", 
           bytes_written, *ppos - bytes_written);

unlock:
    mutex_unlock(&priv->lock);

    return ret;
}

struct ad_range_t {
    u8 index;
    char str[8];
};
struct ad_val_t {
    u8 index;
    s32 val;    // uV
};
// IOCTL 命令定义
#define PCIE_CDEV_MAGIC         'P'
#ifdef EN_DMA
#define CMD_SET_ADDR_LOW        _IOW(PCIE_CDEV_MAGIC, 0, u32)       // 设置内存低32位地址（BAR1+0x200）
#define CMD_SET_ADDR_HIGH       _IOW(PCIE_CDEV_MAGIC, 1, u32)       // 设置内存高32位地址（BAR1+0x204）
#define CMD_SET_CPLD_ADDR       _IOW(PCIE_CDEV_MAGIC, 2, u32)       // 设置CplD初始地址（BAR1+0x210）
#define CMD_SET_LEN             _IOW(PCIE_CDEV_MAGIC, 3, u32)       // 设置数据包长度（BAR1+0x220）
#define CMD_START_DMA           _IO(PCIE_CDEV_MAGIC, 4)             // 启动DMA（假设BAR1+0x238为启动位）
#define CMD_GET_DMA_PHYS_LOW    _IOR(PCIE_CDEV_MAGIC, 5, u32)       // 获取DMA物理地址低32位
#define CMD_GET_DMA_PHYS_HIGH   _IOR(PCIE_CDEV_MAGIC, 6, u32)       // 获取DMA物理地址高32位
#define CMD_SET_DMA_SIZE        _IOW(PCIE_CDEV_MAGIC, 7, size_t)    // 设置DMA内存大小
#endif //EN_DMA
#ifdef EN_IRQ
#define CMD_ENABLE_IRQ          _IO(PCIE_CDEV_MAGIC, 11)
#define CMD_DISABLE_IRQ         _IO(PCIE_CDEV_MAGIC, 12)
#endif /*EN_IRQ*/
#ifdef EN_AD
#define CMD_START_AD            _IO(PCIE_CDEV_MAGIC, 15)
#define CMD_STOP_AD             _IO(PCIE_CDEV_MAGIC, 16)
#define CMD_SET_SAMPLE          _IOW(PCIE_CDEV_MAGIC, 17, u32)
#define CMD_SET_OSR             _IOW(PCIE_CDEV_MAGIC, 18, u32)
#define CMD_SET_RANGE           _IOW(PCIE_CDEV_MAGIC, 19, struct ad_range_t)
#define CMD_GET_AD              _IOWR(PCIE_CDEV_MAGIC, 20, struct ad_val_t)
#endif // EN_AD

// IOCTL 处理
static long pcie_cdev_ioctl(struct file *filp, unsigned int cmd, 
                          unsigned long arg)
{
    struct pcie_t *priv = filp->private_data;
    struct dma_t *dma = &priv->dma;
    struct ad_t *ad = &priv->ad;
    long ret = 0;
    struct ad_range_t range;
    struct ad_val_t ad_val = {0};
#ifdef EN_DMA
    u32 val = 0;
    size_t size = 0;
#endif // EN_DMA

    if (!priv || !priv->bar[PCI_BAR0]) {
        return -ENODEV;
    }
    // 锁保护
    if (mutex_lock_interruptible(&priv->lock)) {
        return -ERESTARTSYS;
    }
    switch (cmd) {
#ifdef EN_DMA
        // 设置内存低32位地址（BAR1+0x200）
        case CMD_SET_ADDR_LOW:
            if (copy_from_user(&val, (void __user *)arg, sizeof(val))) {
                ret = -EFAULT;
                goto unlock;
            }
            iowrite32(val, dma->reg_base + DMA_CPU_PHYS_ADDR_LOW_REG);
            dev_info(priv->dev, "Set addr low: 0x%x\n", val);
            break;
        // 设置内存高32位地址（BAR1+0x204）
        case CMD_SET_ADDR_HIGH:
            if (copy_from_user(&val, (void __user *)arg, sizeof(val))) {
                ret = -EFAULT;
                goto unlock;
            }
            iowrite32(val, dma->reg_base + DMA_CPU_PHYS_ADDR_HIGH_REG);
            dev_info(priv->dev, "Set addr high: 0x%x\n", val);
            break;
        // 设置CplD初始地址（BAR1+0x210）
        case CMD_SET_CPLD_ADDR:
            if (copy_from_user(&val, (void __user *)arg, sizeof(val))) {
                ret = -EFAULT;
                goto unlock;
            }
            iowrite32(val, dma->reg_base + DMA_FPGA_RAM_ADDR_REG);
            dev_info(priv->dev, "Set CplD addr: 0x%x\n", val);
            break;
        // 设置数据包长度（BAR1+0x220）
        case CMD_SET_LEN:
            if (copy_from_user(&val, (void __user *)arg, sizeof(val))) {
                ret = -EFAULT;
                goto unlock;
            }
            iowrite32(val, dma->reg_base + DMA_FPGA_RAM_LEN_REG);
            dev_info(priv->dev, "Set packet len: %u bytes\n", val);

            dma->addr_type = ((dma->alloc_phys >> 32) > 0) ? 1 : 0;
            iowrite32(dma->addr_type, dma->reg_base + DMA_FPGA_DATA_TYPE_REG);
            dev_info(priv->dev, "Set address type: %d\n", dma->addr_type);
            break;
        // 启动 DMA（下发完 packet length 自动启动）
        case CMD_START_DMA:
            dev_info(priv->dev, "DMA started\n");
            // 等待DMA帧完成（中断唤醒）
            if (wait_event_interruptible(dma->wq_frame, dma->frame_done)) {
                dev_err(priv->dev, "DMA frame wait interrupted\n");
                ret = -ERESTARTSYS;
                goto unlock;
            }
            dev_info(priv->dev, "DMA completed successfully\n");
            break;
        // 获取DMA物理地址低32位
        case CMD_GET_DMA_PHYS_LOW:
            val = (u32)(dma->alloc_phys & 0xFFFFFFFF);
            if (copy_to_user((void __user *)arg, &val, sizeof(val))) {
                ret = -EFAULT;
                goto unlock;
            }
            break;
        // 获取DMA物理地址高32位
        case CMD_GET_DMA_PHYS_HIGH:
            val = (u32)((dma->alloc_phys >> 32) & 0xFFFFFFFF);
            if (copy_to_user((void __user *)arg, &val, sizeof(val))) {
                ret = -EFAULT;
                goto unlock;
            }
            break;
        // 设置DMA内存大小（可选，用于调整图片尺寸）
        case CMD_SET_DMA_SIZE:
            if (copy_from_user(&size, (void __user *)arg, sizeof(size))) {
                ret = -EFAULT;
                goto unlock;
            }
            // 释放旧内存，分配新内存
            if (dma->alloc_virt) {
                dma_free_coherent(priv->dev, dma->pl_size, dma->alloc_virt, dma->alloc_phys);
            }
            dma->alloc_virt = dma_alloc_coherent(priv->dev, dma->pl_size, &dma->alloc_phys, GFP_KERNEL);
            if (!dma->alloc_virt) {
                dev_err(priv->dev, "Failed to resize DMA memory to %zu bytes\n", size);
                ret = -ENOMEM;
                goto unlock;
            }
            dma->pl_size = size;
            dma->ps_addr = dma->alloc_phys;
            dev_info(priv->dev, "DMA memory resized to %zu bytes\n", size);
            break;
#endif // EN_DMA
#ifdef EN_IRQ
        case CMD_ENABLE_IRQ:
            // 启用中断 - 实际实现取决于硬件
            iowrite32(0x1, priv->bar[PCI_BAR0] + 0x8); // 假设中断控制寄存器在偏移0x8处
            dev_info(priv->dev, "Interrupts enabled\n");
            break;
        case CMD_DISABLE_IRQ:
            // 禁用中断
            iowrite32(0x0, priv->bar[PCI_BAR0] + 0x8);
            dev_info(priv->dev, "Interrupts disabled\n");
            break;
#endif // EN_IRQ
#ifdef EN_AD
        // 开始 AD 采集
        case CMD_START_AD:
            iowrite32(AD_COMM_START_AD, ad->reg_base + AD_COMM_OFFSET);
            dev_info(priv->dev, "Start AD.\n");
            break;
        // 停止 AD 采集
        case CMD_STOP_AD:
            iowrite32(AD_COMM_STOP_AD, ad->reg_base + AD_COMM_OFFSET);
            dev_info(priv->dev, "Stop AD.\n");
            break;
        case CMD_SET_SAMPLE:
            if (copy_from_user(&val, (void __user *)arg, sizeof(val))) {
                ret = -EFAULT;
                goto unlock;
            }
            ad_set_samp(ad, val);
            dev_info(priv->dev, "Set AD sample %d.\n", val);
            break;
        case CMD_SET_OSR:
            if (copy_from_user(&val, (void __user *)arg, sizeof(val))) {
                ret = -EFAULT;
                goto unlock;
            }
            ad_set_osr(ad, val);
            dev_info(priv->dev, "Set AD OSR %d.\n", val);
            break;
        case CMD_SET_RANGE:
            if (copy_from_user(&range, (void __user *)arg, sizeof(range))) {
                ret = -EFAULT;
                goto unlock;
            }
            ad_set_range(ad, range.index, range.str);
            dev_info(priv->dev, "Set AD range %s.\n", range.str);
            break;
        case CMD_GET_AD:
            iowrite32(0x01, priv->ad.reg_base + AD_MSI_IRQ_MSK);
            if (copy_from_user(&ad_val, (void __user *)arg, sizeof(ad_val))) {
                iowrite32(val, priv->ad.reg_base + AD_MSI_IRQ_MSK);
                ret = -EFAULT;
                goto unlock;
            }
            val = 0;
            val |= (ad_val.index << 16);
            iowrite32(val, priv->ad.reg_base + AD_CH_VAL_OFFSET);
            val = ioread32(priv->ad.reg_base + AD_CH_VAL_OFFSET);
            ad_val.index = (val >> 16) & 0xFF;
            ad_val.val = (val & 0xFFFF);
            switch (ad->range[(ad_val.index % AD_CHANNEL)]) {
            case AD_RANGE_10V:
                ad_val.val *= AD_RANGE_10V_LSB;
                dev_dbg(priv->dev, "Get AD%d=%duV(10V).\n", ad_val.index, ad_val.val);
                break;
            case AD_RANGE_2V5:
                ad_val.val *= AD_RANGE_2V5_LSB;
                dev_dbg(priv->dev, "Get AD%d=%duV(2.5V).\n", ad_val.index, ad_val.val);
                break;
            case AD_RANGE_5V:
                ad_val.val *= AD_RANGE_5V_LSB;
                dev_dbg(priv->dev, "Get AD%d=%duV(5V).\n", ad_val.index, ad_val.val);
                break;
            default:
                dev_info(priv->dev, "Get AD%d=%duV(range error).\n", ad_val.index, ad_val.val);
                break;
            }
            if (copy_to_user((void __user *)arg, &ad_val, sizeof(ad_val))) {
                iowrite32(val, priv->ad.reg_base + AD_MSI_IRQ_MSK);
                ret = -EFAULT;
                goto unlock;
            }
            iowrite32(0x03, priv->ad.reg_base + AD_MSI_IRQ_MSK);
            break;
#endif // EN_AD
        default:
            ret = -ENOTTY;
            break;
    }

unlock:
    mutex_unlock(&priv->lock);

    return ret;
}

#ifdef EN_CDEV
// 字符设备初始化
static int drv_init_cdev(struct char_dev_t *char_dev)
{
    int ret = 0;
    dev_t devno;

    // 为每个设备分配设备号
    ret = alloc_chrdev_region(&devno, 0, MAX_DEVICES, char_dev->name);
    if (ret) {
        dev_err(char_dev->dev, "Failed to allocate devno\n");
        goto err_dev_init;
    }
    char_dev->devno = devno;
    // 创建设备类
    char_dev->cls = class_create(THIS_MODULE, "pcie_cdev_class");
    if (IS_ERR(char_dev->cls)) {
        ret = PTR_ERR(char_dev->cls);
        dev_err(char_dev->dev, "Failed to create class\n");
        goto err_unregister_dev;
    }
    // 字符设备初始化
    cdev_init(&char_dev->cdev, &pcie_cdev_fops);
    char_dev->cdev.owner = THIS_MODULE;
    // 添加字符设备到系统
    ret = cdev_add(&char_dev->cdev, char_dev->devno, 1);
    if (ret) {
        dev_err(char_dev->dev, "Failed to add char_dev\n");
        goto err_class_destroy;
    }
    // 创建设备节点（使用唯一名称）
    device_create(char_dev->cls, NULL, char_dev->devno, NULL, "%s", char_dev->name);

    return 0;

// 错误处理路径
err_class_destroy:
    class_destroy(char_dev->cls);
err_unregister_dev:
    unregister_chrdev_region(char_dev->devno, MAX_DEVICES);
err_dev_init:

    return ret;
}

// 字符设备清理资源
static int drv_exit_cdev(struct char_dev_t *char_dev)
{
    // struct pcie_t *priv = container_of(char_dev, struct pcie_t, char_dev);
    int ret = 0;

    // 销毁设备节点
    device_destroy(char_dev->cls, char_dev->devno);
    // 删除字符设备
    cdev_del(&char_dev->cdev);
    // 销毁设备类
    class_destroy(char_dev->cls);
    // 释放设备号
    unregister_chrdev_region(char_dev->devno, 1);

    return ret;
}
#endif // EN_CDEV

#ifdef EN_IRQ
// Poll 函数 - 用于等待中断
static unsigned int pcie_cdev_poll(struct file *filp, poll_table *wait)
{
    struct pcie_t *priv = filp->private_data;
    unsigned int mask = 0;

    if (!priv) {
        return POLLERR;
    }
    // 添加到等待队列
    poll_wait(filp, &priv->irq.wait_queue, wait);
    // 检查中断状态
    if (atomic_read(&priv->irq.count) > 0) {
        mask |= POLLIN | POLLRDNORM; // 数据可读
    }

    return mask;
}

// 中断服务例程
static irqreturn_t drv_irq_isr(int irq, void *dev_id)
{
    struct pcie_t *priv = dev_id;
    int irq_idx = -1;
    int i;
    u32 status = 0;

    if (!priv || !priv->bar[PCI_BAR0]) {
        return IRQ_NONE;
    }
    // 确定中断索引 (仅对MSI-X/MSI重要)
    if (priv->irq.mode == PCI_IRQ_MSIX || priv->irq.mode == PCI_IRQ_MSI) {
        for (i = 0; i < priv->irq.num; i++) {
            if (priv->irq.vector[i] == irq) {
                irq_idx = i;
                break;
            }
        }
    } else {
        irq_idx = 0; // Legacy中断只有一个
    }
    dev_dbg(priv->dev, "Interrupt %d handled (vector %d)\n", 
             irq, irq_idx);
    if (irq_idx < 0) {
        pr_err("Unknown interrupt %d\n", irq);
        return IRQ_NONE;
    }
    if (IRQ_VEC_MSI_AD == irq_idx) {
#ifdef EN_AD
        // 屏蔽 MSI 中断
        iowrite32(0, priv->irq.reg_base + IRQ_MSI_MASK_REG);
        // 中断内调度工作队列
        if(false == schedule_work(&priv->irq.work_queue)) {
            dev_info(priv->dev, "irq schedule_work failed!\n");
        }
        // 使能 MSI 中断
        iowrite32(1, priv->irq.reg_base + IRQ_MSI_MASK_REG);

        return IRQ_HANDLED;
#endif // EN_AD
    } else {
        // 检查中断状态
        status = ioread32(priv->bar[PCI_BAR0] + 0x4); // 状态寄存器
        if (!(status & (1 << irq_idx))) {
            return IRQ_NONE; // 不是我们的中断
        }
        // 清除中断标志
        iowrite32(status | (1 << irq_idx), priv->bar[PCI_BAR0] + 0x4);
        // 更新中断计数器
        atomic_inc(&priv->irq.count);
        // 唤醒等待进程
        wake_up_interruptible(&priv->irq.wait_queue);
        // 调度工作队列
        schedule_work(&priv->irq.work_queue);
        // 记录中断事件
        dev_dbg(priv->dev, "Interrupt %d handled (vector %d)\n", 
            irq, irq_idx);

        return IRQ_HANDLED;
    }
}

// 工作队列处理函数(中断下半部)
static void work_queue_handler(struct work_struct *work_queue)
{
    struct irq_t *irq = container_of(work_queue, struct irq_t, work_queue);
    struct pcie_t *priv = container_of(irq, struct pcie_t, irq);
    struct dma_t *dma = &priv->dma;
    u32 i = 0;
    // u32 daq_acquire = 0;
    unsigned long flags;    // 用于保存中断状态

    // 这里执行需要在进程上下文中处理的任务
#ifdef EN_AD
    priv->ad.cpl_cnt++;
    priv->ad.cpl_all++;
    // dev_info(priv->dev, "cpl_cnt=%d/%d.\n", priv->ad.cpl_cnt, priv->ad.cpl_all);
#endif // EN_AD
#ifdef EN_DMA
    for (i = 0; i < (dma->frame_size / dma->pkt_len); i++) {
        if (0 == dma_start(dma)) {
            dma_addr_update(dma);
        }
    }
    /* 环形缓冲区指针操作，自旋锁保护*/
    spin_lock_irqsave(&dma->frame_lock, flags);    // 获取自旋锁（保存中断状态）
    // memcpy(&daq_acquire, (const u8 *)priv->dma.alloc_virt + dma->frame_head + 10, sizeof(daq_acquire));
    dma->frame_head = (dma->frame_head + dma->frame_size) % dma->pl_size;
    /* 缓冲区已满 */
    if (dma->frame_head == dma->frame_tail) {
        /* 丢弃最旧数据 */
        dma->frame_tail = (dma->frame_tail + dma->frame_size) % dma->pl_size;
    } else {
        /* 缓冲区有新数据 */
        dma->frame_done = true;
        wake_up_interruptible(&dma->wq_frame);     // 唤醒等待队列（数据帧完成）
        dma->frame_cnt = ((dma->frame_cnt + 1) % (dma->pl_size / dma->frame_size));
    }
    spin_unlock_irqrestore(&dma->frame_lock, flags);    // 释放自旋锁（恢复中断状态）
    // dev_info(priv->dev, "daq_acquire=%d\n", daq_acquire);
#endif // EN_DMA
    dev_dbg(priv->dev, "AD interrupt handled.\n");
    // 注意：在这个函数中，可以安全地调用可能睡眠的函数
}

// 初始化中断系统
static int drv_init_irq(struct irq_t *irq)
{
    struct pcie_t *priv = container_of(irq, struct pcie_t, irq);
    struct pci_dev *pdev = container_of(priv->dev, struct pci_dev, dev);
    int ret = 0, i;
    int max_vecs = 0;
    char irq_name[32] = {0};

    // 初始化等待队列
    init_waitqueue_head(&irq->wait_queue);
    atomic_set(&irq->count, 0);
    irq->mode = 0;
    // 尝试使用 MSI-X
    max_vecs = IRQ_MAX_VEC_MSIX;
    ret = pci_alloc_irq_vectors(pdev, 1, max_vecs, PCI_IRQ_MSIX);
    if (ret > 0) {
        irq->num = ret;
        irq->mode = PCI_IRQ_MSIX;
        dev_info(irq->dev, "Using MSI-X with %d vectors\n", irq->num);
        goto setup_irqs;
    }
    // 尝试使用 MSI
    max_vecs = IRQ_MAX_VEC_MSI;
    ret = pci_alloc_irq_vectors(pdev, 1, max_vecs, PCI_IRQ_MSI);
    if (ret > 0) {
        irq->num = ret;
        irq->mode = PCI_IRQ_MSI;
        dev_info(irq->dev, "Using MSI with %d vectors\n", irq->num);
        goto setup_irqs;
    }
    // 使用 Legacy 中断
    max_vecs = IRQ_MAX_VEC_LGCY;
    ret = pci_alloc_irq_vectors(pdev, 1, max_vecs, PCI_IRQ_LEGACY);
    if (ret < 0) {
        dev_err(irq->dev, "Failed to allocate IRQ vectors (%d)\n", ret);
        return ret;
    }
    irq->num = 1;
    irq->mode = PCI_IRQ_LEGACY;
    dev_info(irq->dev, "Using legacy INTx interrupt\n");

setup_irqs:
    // 获取中断号并注册处理程序
    for (i = 0; i < irq->num; i++) {
        irq->vector[i] = pci_irq_vector(pdev, i);
        if (irq->vector[i] < 0) {
            dev_err(irq->dev, "Invalid IRQ vector for index %d\n", i);
            ret = -EINVAL;
            goto free_irq_vectors;
        }
        // 动态生成带编号的中断名称
        snprintf(irq_name, sizeof(irq_name), "%s_%d", IRQ_NAME, i);
        // 注册中断处理程序
        ret = request_irq(irq->vector[i], drv_irq_isr, 
                          (irq->mode == PCI_IRQ_LEGACY) ? IRQF_SHARED : 0,
                          irq_name, priv);
        if (ret) {
            dev_err(irq->dev, "Failed to request IRQ %d for vector %d\n",
                    irq->vector[i], i);
            goto free_irqs;
        }
    }
    // 初始化工作队列
    INIT_WORK(&irq->work_queue, work_queue_handler);

    return 0;

free_irqs:
    // 清理已分配的中断
    while (i-- > 0) {
        free_irq(irq->vector[i], priv);
    }
free_irq_vectors:
    pci_free_irq_vectors(pdev);
    return ret;
}

// 中断系统清理资源
static void drv_exit_irq(struct irq_t *irq)
{
    struct pcie_t *priv = container_of(irq, struct pcie_t, irq);
    struct pci_dev *pdev = container_of(priv->dev, struct pci_dev, dev);
    int i;

    for (i = 0; i < irq->num; i++) {
        free_irq(irq->vector[i], priv);
    }
    pci_free_irq_vectors(pdev);
    irq->num = 0;
    irq->mode = 0;
}
#endif // EN_IRQ

// PCI 设备探测函数
static int pcie_cdev_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
    struct pcie_t *priv;
    int ret = 0;
    u8 i = 0;

    dev_info(&pdev->dev, "Device: %04x:%04x at %s\n", 
             pdev->vendor, pdev->device, pci_name(pdev));

    // 检查设备是否已初始化
    if (pci_get_drvdata(pdev)) {
        dev_info(&pdev->dev, "Device already initialized\n");
        return -EBUSY;
    }
    // 分配设备结构
    priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
    if (!priv)
        return -ENOMEM;
    // 保存dev设备
    priv->dev = &pdev->dev;
    pci_set_drvdata(pdev, priv);
    // 生成唯一设备名称（使用PCI位置）
    // snprintf(priv->name, sizeof(priv->name), "pcie_cdev_%04x:%02x:%02x.%d",
    //          pci_domain_nr(pdev->bus), pdev->bus->number,
    //          PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
    snprintf(priv->name, sizeof(priv->name), "%s", DRIVER_NAME);
    // 初始化互斥锁
    mutex_init(&priv->lock);
    // 启用PCI设备
    ret = pci_enable_device(pdev);
    if (ret) {
        dev_err(priv->dev, "Failed to enable PCI device\n");
        goto err_free_dev;
    }
    // 请求内存区域
    ret = pci_request_regions(pdev, priv->name);
    if (ret) {
        dev_err(priv->dev, "Failed to request regions\n");
        goto err_disable_dev;
    }
    // 初始化所有 BAR 指针为 NULL
    for (i = 0; i < PCI_MAX_BARS; i++) {
        priv->bar[i] = NULL;
    }
    // 检查并映射所有 BAR
    for (i = 0; i < PCI_MAX_BARS; i++) {
        priv->bar_len[i] = pci_resource_len(pdev, i);
        // BAR0 必须有有效长度
        if (i == PCI_BAR0 && priv->bar_len[i] == 0) {
            dev_err(priv->dev, "Invalid BAR0 size\n");
            ret = -EIO;
            goto err_release_regions;
        }
        // 只映射长度非 0 的 BAR
        if (priv->bar_len[i] > 0) {
            priv->bar[i] = pci_ioremap_bar(pdev, i);
            if (!priv->bar[i]) {
                dev_err(priv->dev, "Failed to map BAR%d\n", i);
                ret = -ENOMEM;
                goto err_unmap_bars;
            }
        } else {
            dev_info(priv->dev, "BAR%d.len=%lld\n", i, priv->bar_len[i]);
        }
    }
#ifdef EN_DMA
    priv->dma.reg_base = priv->bar[PCI_BAR1];
    spin_lock_init(&priv->dma.frame_lock);      // 自旋锁初始化
    // 设置DMA掩码
    if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
        if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
            dev_err(priv->dev, "No suitable DMA available\n");
            ret = -EIO;
            goto err_unmap_bars;
        }
    }
#endif // EN_DMA
    pci_set_master(pdev);
#ifdef EN_IRQ
    // 初始化中断系统
    priv->irq.dev = priv->dev;
    priv->irq.reg_base = priv->bar[PCI_BAR0];
    ret = drv_init_irq(&priv->irq);
    if (ret) {
        dev_err(priv->dev, "Failed to initialize interrupts!\n");
        goto err_unmap_bars;
    }
#endif // EN_IRQ
#ifdef EN_CDEV
    // 字符设备初始化
    priv->char_dev.dev = priv->dev;
    priv->char_dev.name = priv->name;
    ret = drv_init_cdev(&priv->char_dev);
    if (ret) {
        dev_err(priv->dev, "Failed to initialize char device!\n");
        goto err_cleanup_irq;
    }
#endif // EN_CDEV
#ifdef EN_AD
    ret = ad_init(&priv->ad);
    if (ret) {
        dev_err(priv->dev, "Failed to initialize char device!\n");
        goto err_cleanup_irq;
    }
#endif // EN_AD


    dev_info(priv->dev, "PCIe character device %s initialized\n", priv->name);
    dev_info(priv->dev, "BAR%d size: %pa bytes\n", PCI_BAR0, &priv->bar_len[PCI_BAR0]);
#ifdef EN_IRQ
    dev_info(priv->dev, "Using %s with %d interrupt vectors\n",
             priv->irq.mode == PCI_IRQ_MSIX ? "MSI-X" :
             priv->irq.mode == PCI_IRQ_MSI ? "MSI" : "Legacy",
             priv->irq.num);
#endif // EN_IRQ

    return 0;

// 错误处理路径
err_cleanup_irq:
#ifdef EN_IRQ
    drv_exit_irq(&priv->irq);
#endif // EN_IRQ
err_unmap_bars:
    // 逆序释放已映射的 BAR
    while (i--) {
        if (priv->bar[i])
            iounmap(priv->bar[i]);
    }
err_release_regions:
    pci_release_regions(pdev);
err_disable_dev:
    pci_disable_device(pdev);
err_free_dev:
    // devm 会自动释放内存

    return ret;
}

// PCI 设备移除函数
static void pcie_cdev_remove(struct pci_dev *pdev)
{
    struct pcie_t *priv = pci_get_drvdata(pdev);
    u8 i = 0;

    if (!priv) {
        return;
    }
#ifdef EN_CDEV
    // 字符设备 清理资源
    drv_exit_cdev(&priv->char_dev);
#endif // EN_CDEV
#ifdef EN_IRQ
    // 中断系统 清理资源
    drv_exit_irq(&priv->irq);
#endif // EN_IRQ

    // 取消寄存器映射
    for (i = 0; i < PCI_MAX_BARS; i++) {
        if (priv->bar[i]) {
            pci_iounmap(pdev, priv->bar[i]);
        }
    }
    // 释放PCI区域
    pci_release_regions(pdev);
    // 禁用PCI设备
    pci_disable_device(pdev);
    // 销毁互斥锁
    mutex_destroy(&priv->lock);

    dev_info(priv->dev, "PCIe character device %s removed\n", priv->name);
}

// PCI 设备ID表
static const struct pci_device_id pcie_cdev_ids[] = {
    { PCI_DEVICE(0x10ee, 0x9021) },     // Xilinx 示例设备
    { PCI_DEVICE(0x0755, 0x0755) },     // Pango 设备
    { 0, }  // 结束标记
};
MODULE_DEVICE_TABLE(pci, pcie_cdev_ids);

// PCI 驱动结构
static struct pci_driver pcie_cdev_driver = {
    .name = DRIVER_NAME,
    .id_table = pcie_cdev_ids,
    .probe = pcie_cdev_probe,
    .remove = pcie_cdev_remove,
};

// 模块初始化和退出
static int __init pcie_cdev_init(void)
{
    int ret;
    
    ret = pci_register_driver(&pcie_cdev_driver);
    if (ret) {
        pr_err("Failed to register PCI driver\n");
    } else {
        pr_info("PCIe character device driver loaded\n");
    }
    
    return ret;
}

static void __exit pcie_cdev_exit(void)
{
    pci_unregister_driver(&pcie_cdev_driver);
    pr_info("PCIe character device driver unloaded\n");
}

module_init(pcie_cdev_init);
module_exit(pcie_cdev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jason");
MODULE_DESCRIPTION("PCIe Character Device Driver");
MODULE_VERSION("0.1");
